/* JavaLog - pkg tracker 
 * 
 * Copyright (C) 2009 Allyson Lima, Diego Pedro, Victor Freire
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software 
 * Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this 
 * program. If not, see <http://www.gnu.org/licenses/>.
 */

package br.edu.ufcg.ccc.javalog.model;

import java.util.ArrayList;
import java.util.List;

import br.edu.ufcg.ccc.javalog.exceptions.PackageException;

/**
 * A generic class Package
 * 
 * @author Allyson Lima, Diego Pedro, Victor Freire
 * @version 03/12/09
 */
public abstract class Package {

	/**
	 * ID attribute of the package
	 */
	private String ID;

	/**
	 * Sender address attribute
	 */
	private Address senderAddress;

	/**
	 * Recipient address attribute
	 */
	private Address recipientAddress;

	/**
	 * Source store attribute
	 */
	private Franchise sourceFranchise;

	/**
	 * Destination store attribute
	 */
	private Franchise destinationFranchise;

	/**
	 * Current store attribute
	 */
	private Franchise currentFranchise;

	/**
	 * List of the reports attribute
	 */
	private List<ReportEntry> trackingReport;

	/**
	 * Constructor default
	 * 
	 * @param senderAddress
	 *            Address of the sender
	 * @param recipientAddress
	 *            Address of the recipient
	 * @param sourceFranchise
	 *            Source Franchise
	 * @param destinationFranchise
	 *            Destination Franchise
	 * @throws IllegalArgumentException
	 *             Invalid arguments
	 */
	public Package(Address senderAddress, Address recipientAddress,
			Franchise sourceFranchise, Franchise destinationFranchise)
			throws PackageException {
		Validator.validateObject(senderAddress, new PackageException(
				"Received null senderAddress"));
		Validator.validateObject(recipientAddress, new PackageException(
				"Received null recipientAddress"));
		Validator.validateObject(sourceFranchise, new PackageException(
				"Received null sourceFranchise"));
		Validator.validateObject(destinationFranchise, new PackageException(
				"Received null destinationFranchise"));
		this.ID = IDUtil.newID();
		this.senderAddress = senderAddress;
		this.recipientAddress = recipientAddress;
		this.sourceFranchise = sourceFranchise;
		this.destinationFranchise = destinationFranchise;
		this.currentFranchise = sourceFranchise;
		trackingReport = new ArrayList<ReportEntry>();
	}

	/**
	 * Returns the type of the package
	 * 
	 * @return the type of the package
	 */
	public abstract String getType();

	/**
	 * Moves this package to the next franchise
	 */
	public abstract void move() throws PackageException;

	/**
	 * Returns the identifier of the package
	 * 
	 * @return the identifier of the package
	 */
	public String getID() {
		return ID;
	}

	/**
	 * Returns the address of the sender
	 * 
	 * @return the address of the sender
	 */
	public Address getSenderAddress() {
		return senderAddress;
	}

	/**
	 * Returns the address of the recipient
	 * 
	 * @return the address of the recipient
	 */
	public Address getRecipientAddress() {
		return recipientAddress;
	}

	/**
	 * Returns the source store
	 * 
	 * @return the source store
	 */
	public Franchise getSourceFranchise() {
		return sourceFranchise;
	}

	/**
	 * Returns the destination store
	 * 
	 * @return the destination store
	 */
	public Franchise getDestinationFranchise() {
		return destinationFranchise;
	}

	/**
	 * Returns the current store
	 * 
	 * @return the current store
	 */
	public Franchise getCurrentFranchise() {
		return currentFranchise;
	}

	/**
	 * Returns the list of the reports
	 * 
	 * @return the list of the reports
	 */
	public List<ReportEntry> getTrackingReport() {
		return trackingReport;
	}

	/*
	 * public List<ReportEntry> trackingReportNewEntry() { // TODO calculate
	 * trackingReportNewEntry }
	 */

	/**
	 * Sets the store the package is currently kept in.
	 * 
	 * @param currentFranchise
	 *            the new package location
	 * @throws PackageException
	 *             when the store is null
	 */
	public void setCurrentFranchise(Franchise currentFranchise)
			throws PackageException {
		Validator.validateObject(currentFranchise, new PackageException(
				"Store validation failed"));
		this.currentFranchise = currentFranchise;
	}

	/**
	 * Compares two packages
	 * 
	 * @return true if both packages are equal
	 */
	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Package)) {
			return false;
		}
		return getID().equals(((Package) obj).getID());
	}

	/**
	 * HashCode method
	 * 
	 * @return HashCode
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((ID == null) ? 0 : ID.hashCode());
		result = prime
				* result
				+ ((currentFranchise == null) ? 0 : currentFranchise.hashCode());
		result = prime
				* result
				+ ((destinationFranchise == null) ? 0 : destinationFranchise
						.hashCode());
		result = prime
				* result
				+ ((recipientAddress == null) ? 0 : recipientAddress.hashCode());
		result = prime * result
				+ ((senderAddress == null) ? 0 : senderAddress.hashCode());
		result = prime * result
				+ ((sourceFranchise == null) ? 0 : sourceFranchise.hashCode());
		result = prime * result
				+ ((trackingReport == null) ? 0 : trackingReport.hashCode());
		return result;
	}
	
	@Override
	public String toString() {
		return String.format("%s  - - -  De: %s   - -   Para: %s", this.ID, this.sourceFranchise, this.destinationFranchise); 
	}
}
